\lstset{
  escapechar=☺,
  extendedchars=\true,
  inputencoding=utf8
}
\chapter{Perl - podstawy}

\section{Czym jest Perl}
Pert to interpretowalny język programowania napisany przez Larry'ego Walla. Nazwa pochodzi od "Practical Extraction and Report Language". Jest to narzędzie pozwalające szybko pisać małe programy wykonujące drobne prace, jak również - przy zachowaniu pewnej dyscypliny - większe programy wykonujące bardziej skomplikowane zadania.
Powstało kilka języków wykorzystujących pewne cechy Perla. Najbardziej znane z~nich to PHP, Ruby i~Python.

\section{Pierwszy program}
\begin{lstlisting}[language=Perl]
#!/usr/bin/perl 
print "Hello world!\n";
#komentarz
\end{lstlisting}
Pierwsza linijka wskazuje interpreter, druga wyświetla ciąg znaków na ekranie (\verb|\n| to znak przejścia do nowej linii). Komentarz jest ignorowany.

\section{Drukowanie wartości różnych typów}
Drukowanie odbywa się za pomocą funkcji \verb|print|.
\begin{lstlisting}[language=Perl]
print("Ciag znakow\n");
print("Liczby : ", 0xb4, "<-- ta wprowadzona 
	szesnastkowo jako 0xb4 \n");
print("To jest pusta tablica:", (), "<-\n");
print("Tablica liczb: ", 
	(3,1,4,1,5,9,2,6,5,3,5,8,9,7,9,3,2), 
	"\n\n"
);
#tablica poprzez zasieg
print("Zasieg liczb i~zasieg liter:\n", 
	(0..9),"\n", 
	("A".."Z"),"\n", 
	("a".."z"),"\n\n"
);
\end{lstlisting}
\section{Zmienne i~tablice}
W Perlu nazwy zmiennych rozpoczynamy znakiem \verb|$|, natomiast nazwy tablic - \verb|@|.
Przypisanie wartości odbywa się za pomocą operatora \verb|=|.
\begin{lstlisting}[language=Perl]
$liczba = 2.718281828459045235360287;
$lancuch = 'abc';
☺@☺tablica_mieszana = ("ciag znakow", 
	0x28, 'wyraz', 3141592E-6);
\end{lstlisting}
Wydruk odbywa się analogicznie, jak w~przypadku literałów:
\begin{lstlisting}[language=Perl]
print("Wydruk skalarow:\n", 
	$lancuch, "\n", $liczba, "\n\n");
print("Wydruk zapisanej wczesniej tablicy: ",
	 ☺@☺tablica_mieszana, "\n");
\end{lstlisting}
Można też skorzystać z~faktu, iż Perl nazwy zmiennych umieszczone w~podwójnym cudzysłowie (w pojedynczym już nie) zamieni na ich wartości:
\begin{lstlisting}[language=Perl]
print('Ciag "Wynikiem jest $liczba" zostaje zamieniony na ',
	"Wynikiem jest $liczba\n" );
\end{lstlisting}
\subsection{Dostęp do elementów tablicy}
Dostęp do elementów możemy uzyskać za pomocą nawiasów kwadratowych \verb|[]|, gdzie indeks elementu umieszczamy wewnątrz nich, lub poprzez specjalne funkcje:
\begin{lstlisting}[language=Perl]
print("Element tablicy o indeksie 1 to '$tablica[1]', 
	zas element o indeksie -1 to '$tablica[-1]'\n"
);
push(@tablica, 'nowy element');
print("Do tablicy dodano nowy element poprzez push 
	na ostatnia pozycje\n"
);
unshift(@tablica, 'nowy element');
print("Do tablicy dodano nowy element na pierwsza 
	pozycje poprzez funkcje unshit"
);
print('Tablica:',@tablica,"<-\n");
print("Pobranie pierwszego elementu z tablicy (z jego 
	usunieciem z tej tablicy) poprzez funkcje shift: ",
	shift(@tablica),"\n"
);
print("Pobranie ostatniego elementu z tablicy (z jego 
	usunieciem z tej tablicy) poprzez funkcje pop: ",
	pop(@tablica),"\n"
);
\end{lstlisting}
\section{Instrukcje warunkowe, pętle}
Instrukcje warunkowe pozwalają na wykonanie określonych poleceń wtedy, gdy spełnione są określone warunki. Składnię pokazano na przykładzie.
\begin{lstlisting}[language=Perl]
if (warunki1) {
  instrukcje
} elsif (warunki2) {
  inne_instrukcje
} else {
  cos_innego
}
\end{lstlisting}
Warto tutaj zwrócić uwagę na słowo kluczowe \verb|elsif|, nie \verb|elseif|.
\textbf{Uwaga!} W~przeciwieństwie np. do języka~C w~Perlu instrukcja nie może występować bezpośrednio po warunku - musi znajdować się wewnątrz nawiasów klamrowych.

Pętle \verb|while|, \verb|do while|, \verb|for| są zaimplementowane w~sposób umożliwiający korzystanie z~nich w~sposób taki sam, jak w~C.
\begin{lstlisting}[language=Perl]
while ($n <= 100) {
  print $n++, "\n";
}

do {
    instrukcja
} while (wyrazenie logiczne);

for ($n = 0; $n <= 10; $n++) {
  print "$n\n";
}
\end{lstlisting}
Istnieją także odpowiedniki \verb|until| dla pętli \verb|while|, które zaprzeczają warunek logiczny testowanego wyrażenia.
\section{Wyrażenia regularne}
Wyrażenia regularne mogą służą do wydobywania z~tekstu ciągów znaków zgodnych z~podanym w~formie wyrażania schematem budowy. Prostym przykładem może być tutaj wydobywanie pojedynczych liczb, słów. Często są one stosowane do walidacji wprowadzonych danych pod kątem poprawności formatu, np. data w~formacie RRRR-MM-DD. Dokładne sprawdzenie (wyrzucające np. 31 luty jako błąd) ciężko przeprowadzić za pomocą wyrażeń regularnych, jednak zastosowanie ich do sprawdzenia istnienia oraz wydobycia z~ciągu znaków listy konkretnych wartości liczbowych (rok, miesiąc, dzień) znacznie ułatwi pracę.

W wyrażeniach regularnych możemy stosować ciągi znaków tak, jak przy normalnym wyszukiwaniu, możemy także tworzyć klasy znaków, jakie będą kwalifikować się jako "dopasowanie". Robimy to poprzez umieszczenie listy pasujących znaków w~nawiasach kwadratowych \verb|[]|, np \verb|[abc]|, \verb|[a-z]|, lub kilka naraz: \verb|[ABCa-z0-9]|.

\begin{table}
  \centering
  \caption{Dopasowania}
  \begin{tabular}{|l|c|}
  \hline
  \verb|\w| & dopasowuje znaki alfanumeryczne i~\verb|_| \\
  \verb|\W|	& dopasowuje znaki poza alfanumeryczymi i~\verb|_| \\
  \verb|\s|	& dopasowuje białe znaki (spacje, tabulatory, znak nowej linii) \\
  \verb|\S|	& dopasowuje znaki nie będące białymi znakami \\
  \verb|\d|	& dopasowuje cyfry, tak jak \verb|[0-9]| \\
  \verb|\D|	& dopasowuje znaki, które nie są cyframi \\
  \hline
  \end{tabular}
\end{table}

Klasę znaków można zanegować znakiem \verb|^|.

\begin{table}
  \centering
  \caption{Metaznaki}
  \begin{tabular}{|l|c|}
  \hline
  \verb|^|	&początek ciągu \\
  \verb|$|	&koniec ciągu \\
  .	&jakikolwiek znak \\
  *	&dopasowanie 0 lub więcej razy \\
  +	&dopasowanie 1 lub więcej razy \\
  ?	&dopasowanie 0 lub 1 raz albo: nie-zachłanne \\
  \verb#|#	&alternatywa \\
  \verb|()|	&grupowanie \\
  \verb|[]|	&zestaw (klasa) znaków \\
  \verb|{}|	&modyfikator ilości powtórzeń \\
  \verb|\| &sekwencja ucieczki dla znaków specjalnych \\
  \hline
  \end{tabular}
\end{table}

\begin{table}
  \centering
  \caption{Modyfikatory powtórzeń}
  \begin{tabular}{|l|c|}
  \hline
  a*	&zero lub więcej razy \\
  a+	&raz lub więcej razy \\
  a?	&wystąpienie lub jego brak \\
  \verb|a{m}| &	dokładnie m~razy \\
  \verb|a{m,}| & m~lub więcej razy \\
  \verb|a{m,n}|	& przynajmniej~m i~najwyżej n~razy \\
  \hline
  \end{tabular}
\end{table}

\subsection{Wyrażenia regularne w~[Pp]erlu}
Korzystać z~wyrażeń w~Perlu można za pomocą operatorów. Pierwszy z~nich to operator dopasowania:
\begin{lstlisting}[language=Perl]
if(m/wzor/) # testuje, czy zmienna $_ zawiera podany wzor
\end{lstlisting}
Drugim jest operator zamiany:
\begin{lstlisting}[language=Perl]
s/wzor/nacos/; # zamiana
\end{lstlisting}
Zamieni to tylko pierwsze wystąpienie danego wzoru, zmienić ten sposób działania można za pomocą modyfikatorów g(znajduje wszystkie wystąpienia); modyfikator i~spowoduje wyszukiwanie dopasowania bez zwracania uwagi na wielkość liter (case insensitive).
\subsection{Wyrażenia regularne w~innych językach programowania}
Przykładowe zastosowanie wyrażeń regularnych w~PHP (flagment działającego systemu służącego do wykrywania fragmentów tekstu ze zmiennej \verb|$_POST['sharebox']|, które są linkami. Instrukcje do ich późniejszego zastosowania zostały pominięte):
\begin{lstlisting}[language=PHP]
preg_match_all(
 '#(http://|http://www.|https://|https://www.|www.)
 	([a-zA-Z0-9./]+)#', 
 $_POST['sharebox'], 
 $subject2); 
	//wyciagam linki z wpisu
	//formy www. , http:// , http://www. 
	// + wariant https
$linki_laduj = 
 (preg_replace(
	'#(http://|https://|)(www.|)
		([a-zA-Z0-9/]+)\.([a-zA-Z0-9./]+)#', 
	'http://$2$3.$4', 
	implode($subject2[0], 
	' '))); // string linkow z poczatkiem http://
\end{lstlisting}

Zastosowanie wyrażeń regularnych w~Java do przepuszczenia z~danych wejściowych tylko zestawu znaków alfanumerycznych:
\begin{lstlisting}[language=Java]
# val typu String
val = val.replaceAll("[^A-Za-z0-9\\. ]", "");
\end{lstlisting}
\section{Perl - obsługa plików tekstowych}
Do korzystania w~skrypcie z~plików należy najpierw źródłowy lub docelowy plik otworzyć, przyporządkowując do niego uchwyt pliku. 
Służy do tego funkcja open, której sygnatura może wyglądać następująco (3 argumenty).
\begin{lstlisting}[language=Perl]
open(UCHWYT,"TRYB",$nazwapliku)
\end{lstlisting}
Ponieważ w~razie niepowodzenia funkcja zwraca wartość logiczną false, stosowny komunikat można wyświetlić stosując prosty zabieg:
\begin{lstlisting}[language=Perl]
open(UCHWYT,"TRYB",$nazwapliku) or die "nie mozna 
	otworzyc pliku $nazwapliku\;"
\end{lstlisting}
TRYB parametr określa tryb dostępu z~oznaczeniami:
\begin{itemize}
\item \verb|<| do odczytu
\item \verb|>| do zapisu
\item \verb|>>| tryb dopisywania
\end{itemize}
Analogiczną funkcją jest \verb|close| zamykająca otwarty plik

Odczyt z~pliku linia po linii dokonuje się za pomocą pętli
\begin{lstlisting}[language=Perl]
while(<UCHWYT>)
{
 #zawartosc aktualnie przetwarzanej linii
 #znajduje sie w~domyslnej zmiennej $_
 instrukcje;
}
\end{lstlisting}
Przy końcu pliku pętla zostaje przerwana.
Zapisu można dokonać podając uchwyt do funkcji print:
\begin{lstlisting}[language=Perl]
print UCHWYT "Wpisywana zawartosc $_\n";
\end{lstlisting}

Przykładowy program - dokłada twarte spacje, by zapobiec spójnikom z~pojedynczych liter "wiszenie" na końcu linii.
\begin{lstlisting}[language=Perl]
while(<>) { 
  s/(\s[a-zA-Z])\s([a-zA-ZżółćęśąźńŻÓŁĆĘŚĄŹŃ])/$1~$2/g; 
  print; 
}
\end{lstlisting}
\subsection{Edycja edytorska - dołożenie twartych spacji po spójnikach}
Program dokłada twarte spacje po spójnikach we wszystkich plikach .tex z~katalogu tex/ umieszczonego w~tym samym miejscu, co poniższy skrypt:
\begin{lstlisting}[language=Perl]
# obsluga kodowania utf8
binmode(STDIN, ":encoding(utf8)");
binmode(STDOUT, ":utf8");
undef $/; # aby wczytac caly plik, nie po linii

opendir(KATALOG,"./tex/"); # lista plikow do tablicy
 @pliki = grep { /\.tex$/ } readdir KATALOG;
closedir KATALOG;

foreach $plik (@pliki) { # dla kazdego pliku
 open(TEX, 'tex/'.$plik) || die "Blad otwierania pliku";
 $_ = <TEX>;
 close(TEX);
 s/(\s[aAiIoOuUwWzZ])\s([a-zA-ZżółćęśąźńŻÓŁĆĘŚĄŹŃ])/$1~$2/g;
 open(TEX, '> tex/'.$plik) || die "Blad otwierania pliku";
 print TEX $_;	
 close(TEX);
 print "Przetworzylem $plik\n";
}
\end{lstlisting}